////////////////////////////////////////////////
// DESCRIPTION:
//    Thread synchronization object support
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//

#pragma once
#include "Handle.h"

namespace FusionWare
{
    extern BOOL InPowerHandler();

    /////////////////////////////////////////////////////////
    // Description:
    //    Win32 Thread support classes
    //
    // Remarks:
    //    Contains a set of classes for managing threads and
    //    synchronization. Several variations of an Auto Locking
    //    template exist for automatically locking and then unlocking
    //    a synchronization object when the enclosing scope exits
    //    following the Resource Allocation Is Initialization (RAII) idiom.
    //    These help to clean up error handling code as the locked objects
    //    are automatically unlocked. The error handling code can simply
    //    return instead of using goto cleanup or other such constructs
    //    to insure the lock is always released.
    //
    namespace Threads
    {
        /////////////////////////////////////////////////////
        // Description:
        //    Provides context specifc synchronization
        //
        // Remarks:
        //    This static class provides functions that are implemented in context
        //    specific libraries. There are 3 different implementations of this
        //    class:
        //
        // @table
        // Library                              Description
        // ----------------------------------   ---------------------------------------------------------------------------
        //  FusionWare.Threads.SingleThreaded   NOP Stub implementations for single threaded environments like boot loaders
        //  FusionWare.Threads.Win32            FULL Win32 Multi Threading (For use in applications and drivers)
        //  FusionWare.Threads.DeferredInit     Defered init support for scenarios starting in single threaded but later switch to multi-threaded, like an OAL.
        // 
        // @table
        // Library                              Included in
        // ----------------------------------   ----------------
        //  FusionWare.Threads.SingleThreaded   FusionWare.Boot
        //  FusionWare.Threads.Win32            FusionWare.DFX
        //  FusionWare.Threads.DeferredInit     FusionWare.OAL
        //
        // Implementation Note:
        //    Due to MS use of pre-processor for implementing
        //    the standard versions of these "functions" on
        //    some platforms this class cannot use the exact
        //    same names even though they are static methods
        //    of a class... (Particullarly the interlocked functions)
        //
        class ThreadingModel
        {
        public:
            // Static class for threading model specif implementations of 
            // critical section support.
            class CriticalSection
            {
            public:    
                static void Init(CRITICAL_SECTION* pCS);
                static void Enter(CRITICAL_SECTION* pCS);
                static void Leave(CRITICAL_SECTION* pCS);
                static void Delete(CRITICAL_SECTION* pCS);
                static bool TryEnter(CRITICAL_SECTION* pCriticalSection); 
            };

            // Group = Interlockedxxx functions

            long AtomicIncrement(long* pAddend);
            long AtomicDecrement(long* pAddend);
            long AtomicExchange(long* pTarget, long Value);
            long AtomicCompareExchange(IN OUT long* pDestination, long Exchange, long Comperand);
            long AtomicExchangeAdd(long* Addend, long Value);

            // group = 
            
            // Handles all deferred init functionality once threading is enabled.
            // For a Windows CE OAL this should be called from a IOCTL_HAL_POSTINIT
            // handler. FusionWare::OAL::StdOalImpl::PostInit() does that automatically.
            static void DoDeferredInit();
        };

        ///////////////////////////////////////////////////////////////////
        // Description:
        //    Special power handler aware Automatic Lock/Unlock
        //
        // Input:
        //    LockType type of object to lock  
        //    
        // Remarks:
        //    Special version of AutoLock for Windows CE Power Handler support
        //    as critical section APIs MUST not be called in power
        //    handler modes
        //
        template<class LockType>
        class TAutoLock
        {
        public:
            ///////////////////////////////////////////////////////
            // Description: 
            //    Constucts a new lock
            //
            // Input: 
            //    rlt            - Reference to an instance of the LockType 
            //    InPowerHandler - Flag indicating the power handler state
            //
            // Remarks: 
            //    If InPowerHandler returns true then this is effectively
            //    a NO-OP this is important in driver power down code where 
            //    synchronization is problematic at best.
            // 
            TAutoLock(LockType& rlt)
            { 
                if(!InPowerHandler())
                { 
                   m_pLock=&rlt;
                   m_pLock->Lock();
                }
                else
                   m_pLock=NULL;
            };

            ///////////////////////////////////////////////////////
            // Description: 
            //    Constucts a new lock
            //
            // Input: 
            //    rlt            Reference to an instance of the LockType 
            //    InPowerHandler Flag indicating the power handler state
            //
            // Remarks: 
            //    If InPowerHandler returns true then this is effectively
            //    a NO-OP. This is important in driver power down code
            //    where synchronization is problematic at best.
            // 
            TAutoLock(LockType* plt)
            { 
                if(!InPowerHandler())
                { 
                   m_pLock=plt;
                   m_pLock->Lock();
                }
                else
                   m_pLock=NULL;
            };

            ///////////////////////////////////////////////////////
            // Description: 
            //    Destucts a lock object (Unlocks the LockType instance)
            //
            // Remarks: 
            //    If IsInPwrHdlr returned TRUE in the constructor then this is
            //    effectively a NO-OP. This is used in Driver Power handler
            //    code where synchronization is problematic at best.
            // 
            ~TAutoLock()
            {
                if(m_pLock)
                   m_pLock->Unlock();
            }

        private:
            LockType* m_pLock;
        };

        // Auto unlocking for types where the lock is already acquired
        // and must be released on exit.
        // NOTE:
        //   THis is not safe for use in power handlers
        //
        template<class LockType>
        class TAutoUnlock
        {
            public:
            TAutoUnlock(LockType& rlt) : m_Lock(rlt) {};
            ~TAutoUnlock() { m_Lock.Unlock(); }

            private:
            LockType& m_Lock;
        };

        /////////////////////////////////////////////////////
        // Description:
        //    Critical section synchronization
        //
        // Remarks:
        //    Initializing the CS in the constructor and
        //    deletes it in the destructor.
        //    Implements Lock() and Unlock() so it may be used 
        //    with TAutoLock<>
        //
        class CriticalSection
        {
        public:
            CriticalSection(const bool DoInit=true)
            {
                // force the CS to all 0 so that IsInitialized() can work
                memset(&cs, 0, sizeof(cs));
                if(DoInit)
                    Init();
            }

            CriticalSection(const CriticalSection& cs) { this->cs=cs.cs; }
            CriticalSection(const CRITICAL_SECTION& cs) { this->cs=cs; }

            ~CriticalSection()
            { 
                if(IsInitialized())
                    ThreadingModel::CriticalSection::Delete(&this->cs);
            }
            
            void Init()
            { 
                if(!IsInitialized())
                    ThreadingModel::CriticalSection::Init(&this->cs);
            }

            bool IsInitialized()
            {
                // cs.hCrit is set up by the OS in ::InitializeCriticalSection()
                return 0!=this->cs.hCrit;
            }
            

            void Lock()
            { 
                if(IsInitialized())
                    ThreadingModel::CriticalSection::Enter(&this->cs);
            }

            void Unlock()
            { 
                if(IsInitialized())
                    ThreadingModel::CriticalSection::Leave(&this->cs);
            }

            typedef FusionWare::Threads::TAutoLock<CriticalSection> TAutoLock;
        
        private:
            CRITICAL_SECTION cs;
        };

        //////////////////////////////////////////////////////
        // {partof:FusionWare::Threads}
        // Description:
        //    Instantiates an autolock for the specified type
        //
        // Input:
        //    m Object instance to perform lock on (usually a class member)
        //
        // Note:
        //    This macro is being deprecated and will not be supported in future
        //    versions.
        //
        #define AUTO_CS(m) FusionWare::Threads::CriticalSection::TAutoLock auto_lock(m)

        /////////////////////////////////////////////////////
        // Description:
        //    Mutex synchronization
        //
        // Remarks:
        //    The Mutex is uninitialized in the default constructor.
        //
        //    Implements Lock() and Unlock() so it may be used 
        //    with TAutoLock<>
        //
        class Mutex : public FusionWare::Win32::TWin32Handle<NULL>
        {
        public:
            Mutex() {}                  
            Mutex(const Mutex& mtx) 
                : FusionWare::Win32::TWin32Handle<NULL>(mtx)
            {
            }
            ~Mutex() { }

            Mutex& operator=(HANDLE h)       { FusionWare::Win32::TWin32Handle<NULL>::operator=(h); return *this; }
            Mutex& operator=(const Mutex& R) { FusionWare::Win32::TWin32Handle<NULL>::operator=(R); return *this; }
            
            ///////////////////////////////////////////////////////
            // Description: 
            //    Creates a new Mutex
            //
            // Input: 
            //    Name      - [ Defult = NULL ] Name of the Mutex 
            //    InitOwner - [ Default = FALSE ] Flag indicating if the
            //                calling thread should own the mutex after creation.
            //    pSec      - [Default = NULL] Security attributes
            //
            bool Create(const TCHAR* Name=NULL, bool InitOwner=false, SECURITY_ATTRIBUTES* pSec=NULL)
            {
                operator=(CreateMutex(pSec, BOOL(InitOwner), Name));
                return IsValid();
            }
            
            // Acquires the Mutex
            bool Lock(UINT32 Timeout=INFINITE)
            {
                return WAIT_OBJECT_0 != Wait(Timeout);
            }
            
            // Releases the Mutex
            void Unlock()
            { 
                ASSERT(IsValid());
                ReleaseMutex(this->Win32Handle);
            }

            typedef FusionWare::Threads::TAutoLock<Mutex> TAutoLock;
        };

        //////////////////////////////////////////////////////
        // {partof:FusionWare::Threads}
        // Description:
        //    Instantiates an autolock for the specified type
        //
        // Input:
        //    m   - Mutex Object instance to perform lock on (usually a class member)
        //
        // Note:
        //    This macro is being deprecated and will not be supported in future
        //    versions.
        //
        #define AUTO_MUTEX(m) FusionWare::Threads::Mutex::TAutoLock auto_lock(m)

        /////////////////////////////////////////////////////
        // Description:
        //    Event synchronization
        //
        // Remarks:
        //    The Event is uninitialized in the default constructor.
        //
        class Event : public FusionWare::Win32::TWin32Handle<NULL>
        {
        public:
            Event()     { }
            Event(const Event& Evt) 
                : FusionWare::Win32::TWin32Handle<NULL>(Evt)
            {
            }
           
            ~Event()    { }

            Event& operator=(HANDLE h)       { FusionWare::Win32::TWin32Handle<NULL>::operator=(h); return *this;}
            Event& operator=(const Event& R) { FusionWare::Win32::TWin32Handle<NULL>::operator=(R); return *this;}

            BOOL Set()   { return SetEvent(this->Win32Handle); }
            BOOL Reset() { return ResetEvent(this->Win32Handle); }
            BOOL Pulse() { return PulseEvent(this->Win32Handle); }

            ///////////////////////////////////////////////////////
            // Description: 
            //    Waits for the Event
            //
            // Input: 
            //    TimeOut [Default = INFINITE] Time in milliseconds to wait 
            //
            // Returns: 
            //     WAIT_OBJECT_0 Event was triggered
            //     WAIT_TIMEOUT  Timeout occured waiting for the object 
            //     WAIT_FAIL     Event Handle was bad
            //     
            DWORD Wait(DWORD TimeOut=INFINITE)
            {
                return FusionWare::Win32::TWin32Handle<NULL>::Wait(TimeOut);
            }

            ///////////////////////////////////////////////////////
            // Description: 
            //    Creates a new Event
            //
            // Input: 
            //    Name        - [Default = NULL] Name for the Event
            //    ManualReset - [Default = FALSE] Flag indicating if the Event is manual reset
            //    InitState   - [Default = FALSE] Flag to indicate the initial state of the event
            //    pSec        - [Default = NULL] Security attributes
            //
            bool Create(const TCHAR* Name=NULL, bool ManualReset=FALSE, bool InitState=FALSE, SECURITY_ATTRIBUTES* pSec=NULL)
            {
                Close();
                operator=(CreateEvent(pSec, BOOL(ManualReset), BOOL(InitState), Name));
                return IsValid();
            }

// event data functions only come along with pkfuncs.h,
// which is pulled in when WINCEOEM is set
#ifdef WINCEOEM
            ///////////////////////////////////////////////////////
            // Description: 
            //    Associates data with an event
            //
            // Input: 
            //    Val - data to associate with the event
            //
            // Returns: 
            //    BOOL 
            //     
            // Remarks: 
            //    Associates an arbitrary 32 bit value with an event
            //    This data can be retrieved via GetData(). This is
            //    most commonly used for a flag to inform a worker
            //    thread that it should shut down. 
            //
            BOOL SetData(DWORD Val)
            {
                SetEventData(this->Win32Handle, Val);
            }

            ///////////////////////////////////////////////////////
            // Description: 
            //    Retrieves data associated with an event
            //
            // Returns: 
            //    DWORD - associated data 
            //     
            // Remarks: 
            //    Retrieves an arbitrary 32 bit value associated with
            //    an event. This data can be retrieved via GetData().
            //    This is most commonly used for a flag to inform a
            //    worker thread that it should shut down. 
            //
            DWORD GetData()
            {
                GetEventData(this->Win32Handle);
            }
#endif
        };

        // TODO: Add semaphore class
    }
}